package com.ding.courier;

import com.ding.common.*;

import java.io.IOException;
import java.net.Socket;
import java.util.UUID;
import java.util.logging.Logger;

public class CommanderHolder {

    private static Logger logger = Logger.getLogger("mynat");

    private String password;

    private CommanderChannel commander;

    //轮询间隔增加值
    private int pollingIntervalIncrease;

    //开始轮询时间
    private int startPollingInterval;

    //最大轮询事件
    private int maxPollingInterval;

    private class Polling {

        int currentPollingInterval = startPollingInterval;

        void increase() {

            if (this.currentPollingInterval < maxPollingInterval) {
                this.currentPollingInterval += pollingIntervalIncrease;
            }
        }

        void reset() {
            this.currentPollingInterval = startPollingInterval;
        }

        int getCurrentPollingInterval() {
            return currentPollingInterval;
        }

    }

    private String commanderHost;

    private int commanderPort;

    private CPool pool;


    private boolean stopped = false;

    private Polling polling = new Polling();

    void start() {
        Threads.exe(() -> {
            Socket socket;
            try {
                socket = new Socket(commanderHost, commanderPort);
            } catch (IOException e) {

                if (stopped) {
                    return;
                }

                logger.warning("无法连接至指挥官...");
                Waiter.setTimeout(this::start, polling.getCurrentPollingInterval());
                polling.increase();
                return;
            }

            CommanderChannel channel = new CommanderChannel(socket, password, pool);

            channel.setId(UUID.randomUUID().toString());

            channel.setAfterCloseStrategy(() -> {

                pool.closeAndRemoveByIntroducerId(channel.getId());

                this.commander = null;
                if (stopped) {
                    return;
                }
                Waiter.setTimeout(this::start, polling.getCurrentPollingInterval());
                polling.increase();
            });


            channel.sendMsg(new Message().type(Constant.NEW_COMMAND).id(channel.getId()).password(password));

            Waiter.TaskHolder taskHolder = Waiter.setTimeout(channel::close, 2000);
            Message message = channel.readMsg();
            taskHolder.clear();

            System.out.println("指令通信建立一次,并成功应答");

            if (message.getType().equals(Constant.HEARTBEAT)) {

                polling.reset();

                this.commander = channel;

                //开始心跳
                int time = message.getHeartbeatInterval();

                Message m = new Message().type(Constant.HEARTBEAT);

                Heartbeat heartbeat = new Heartbeat(time, 0) {
                    @Override
                    protected void hearbeat() {

                        System.out.println("发送心跳");
                        channel.send(m);
                    }
                };

                System.out.println("心跳线程开始工作");
                heartbeat.start();

                AfterCloseStrategy strategy = channel.getAfterCloseStrategy();
                channel.setAfterCloseStrategy(()->{
                    strategy.afterClose();
                    heartbeat.clear();
                });

                System.out.println("通道开始工作");
                channel.startReadCommand();
            }


        });

    }


    public void stop() {
        this.stopped = true;
        if (this.commander != null) {
            this.commander.close();
        }
    }

    public void sendMsg(Message message) {
        if (this.commander != null) {
            this.commander.send(message);
        }
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setPollingIntervalIncrease(int pollingIntervalIncrease) {
        this.pollingIntervalIncrease = pollingIntervalIncrease;
    }

    public void setStartPollingInterval(int startPollingInterval) {
        this.startPollingInterval = startPollingInterval;
    }

    public void setMaxPollingInterval(int maxPollingInterval) {
        this.maxPollingInterval = maxPollingInterval;
    }

    public void setCommanderHost(String commanderHost) {
        this.commanderHost = commanderHost;
    }

    public void setCommanderPort(int commanderPort) {
        this.commanderPort = commanderPort;
    }

    public void setPool(CPool pool) {
        this.pool = pool;
    }
}
